use thiserror::Error;

/// Error type for the cluster node manager
#[derive(Error, Debug)]
pub enum Error {
    /// Configuration error
    #[error("Configuration error: {0}")]
    Config(#[from] config::ConfigError),

    /// I/O error
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    /// Serialization error
    #[error("Serialization error: {0}")]
    Serialization(#[from] serde_json::Error),

    /// YAML serialization error
    #[error("YAML error: {0}")]
    Yaml(#[from] serde_yaml::Error),

    /// Raft error
    #[error("Raft error: {0}")]
    Raft(String),

    /// Storage error
    #[error("Storage error: {0}")]
    Storage(String),

    /// Network error
    #[error("Network error: {0}")]
    Network(String),

    /// API error
    #[error("API error: {0}")]
    Api(String),

    /// Health check error
    #[error("Health check error: {0}")]
    HealthCheck(String),

    /// Failover error
    #[error("Failover error: {0}")]
    Failover(String),

    /// Node not found
    #[error("Node not found: {0}")]
    NodeNotFound(String),

    /// Cluster error
    #[error("Cluster error: {0}")]
    Cluster(String),

    /// Authentication error
    #[error("Authentication error: {0}")]
    Auth(String),

    /// Rate limit error
    #[error("Rate limit exceeded")]
    RateLimit,

    /// Invalid request
    #[error("Invalid request: {0}")]
    InvalidRequest(String),

    /// Internal server error
    #[error("Internal server error: {0}")]
    Internal(String),

    /// Timeout error
    #[error("Timeout error: {0}")]
    Timeout(String),

    /// Generic error
    #[error("Error: {0}")]
    Generic(String),
}

impl Error {
    /// 构造一个 Raft 相关错误（统一封装字符串信息）
    pub fn raft<T: ToString>(msg: T) -> Self {
        Self::Raft(msg.to_string())
    }

    /// 构造一个配置错误（包装成 config::ConfigError::Message 以复用枚举 variant）
    pub fn config<T: ToString>(msg: T) -> Self {
        Self::Config(config::ConfigError::Message(msg.to_string()))
    }

    /// 构造一个存储相关错误
    pub fn storage<T: ToString>(msg: T) -> Self {
        Self::Storage(msg.to_string())
    }

    /// 构造一个网络相关错误
    pub fn network<T: ToString>(msg: T) -> Self {
        Self::Network(msg.to_string())
    }

    /// 构造一个 API 层错误
    pub fn api<T: ToString>(msg: T) -> Self {
        Self::Api(msg.to_string())
    }

    /// 构造一个健康检查错误
    pub fn health_check<T: ToString>(msg: T) -> Self {
        Self::HealthCheck(msg.to_string())
    }

    /// 构造一个故障转移相关错误
    pub fn failover<T: ToString>(msg: T) -> Self {
        Self::Failover(msg.to_string())
    }

    /// 构造一个集群通用错误
    pub fn cluster<T: ToString>(msg: T) -> Self {
        Self::Cluster(msg.to_string())
    }

    /// 构造一个认证/鉴权错误
    pub fn auth<T: ToString>(msg: T) -> Self {
        Self::Auth(msg.to_string())
    }

    /// 构造一个客户端请求参数无效错误
    pub fn invalid_request<T: ToString>(msg: T) -> Self {
        Self::InvalidRequest(msg.to_string())
    }

    /// 构造一个内部错误（通常代表未知/未分类异常）
    pub fn internal<T: ToString>(msg: T) -> Self {
        Self::Internal(msg.to_string())
    }

    /// 构造一个超时错误
    pub fn timeout<T: ToString>(msg: T) -> Self {
        Self::Timeout(msg.to_string())
    }

    /// 构造一个通用兜底错误
    pub fn generic<T: ToString>(msg: T) -> Self {
        Self::Generic(msg.to_string())
    }
}

/// Result type alias
pub type Result<T> = std::result::Result<T, Error>;

/// Cluster error type alias
pub type ClusterError = Error;

/// Convert from anyhow::Error
impl From<anyhow::Error> for Error {
    fn from(err: anyhow::Error) -> Self {
        Self::Generic(err.to_string())
    }
}

/// Convert from openraft error
impl From<openraft::error::RaftError<crate::NodeId>> for Error {
    fn from(err: openraft::error::RaftError<crate::NodeId>) -> Self {
        Self::Raft(err.to_string())
    }
}

/// Convert from HTTP status code
impl From<axum::http::StatusCode> for Error {
    fn from(status: axum::http::StatusCode) -> Self {
        Self::Api(format!("HTTP error: {}", status))
    }
}

/// Convert to HTTP status code
impl Error {
    pub fn status_code(&self) -> u16 {
        match self {
            Error::NodeNotFound(_) => 404,
            Error::Auth(_) => 401,
            Error::RateLimit => 429,
            Error::InvalidRequest(_) => 400,
            Error::Timeout(_) => 408,
            _ => 500,
        }
    }
}
